<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Tutorial: View Adaptors</title>
<link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset">
<link rel="up" href="../stl_interfaces.html" title="Chapter 36. Boost.STLInterfaces">
<link rel="prev" href="tutorial___reverse_iterator_.html" title="Tutorial: reverse_iterator">
<link rel="next" href="tutorial___closure__and__adaptor_.html" title="Tutorial: closure and adaptor">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../boost.png"></td>
<td align="center"><a href="../../../index.html">Home</a></td>
<td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="tutorial___reverse_iterator_.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stl_interfaces.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="tutorial___closure__and__adaptor_.html"><img src="../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="boost_stlinterfaces.tutorial__view_adaptors"></a><a class="link" href="tutorial__view_adaptors.html" title="Tutorial: View Adaptors">Tutorial:
    View Adaptors</a>
</h2></div></div></div>
<p>
      C++20 introduced views and view adaptors. The adaptors have a nice "pipe"
      syntax, like:
    </p>
<pre class="programlisting"><span class="keyword">for</span> <span class="special">(</span><span class="keyword">auto</span> <span class="identifier">x</span> <span class="special">:</span> <span class="identifier">range</span> <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">reverse</span> <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">take</span><span class="special">(</span><span class="number">10</span><span class="special">))</span> <span class="special">{</span>
    <span class="comment">// Here, we get the last 10 values of range, in reverse order.</span>
<span class="special">}</span>
</pre>
<p>
      However, the C++20 standard provides you no help in making your own views and
      view adaptors that work this way. C++23 introduces <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">range_adaptor_closure</span></code>,
      a base type that allows your view adaptors and <code class="computeroutput"><span class="identifier">std</span></code>
      view adaptors to interoperate in pipe expressions.
    </p>
<p>
      Boost.STLInterfaces provides a type <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">range_adaptor_closure</span></code>
      that is defined to be a work-alike of <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">range_adaptor_closure</span></code>
      in pre-C++23 builds, and is an alias for <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">range_adaptor_closure</span></code>
      in C++23 and later.
    </p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
        For GCC 12, it was necessary to make <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">range_adaptor_closure</span></code>
        an alias for <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">__adaptor</span><span class="special">::</span><span class="identifier">_RangeAdaptorClosure</span></code>. This is necessary
        because all the <code class="computeroutput"><span class="identifier">std</span></code> views
        will only combine with views derived from <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">__adaptor</span><span class="special">::</span><span class="identifier">_RangeAdaptorClosure</span></code>.
        Even naming a namespace that contains <code class="computeroutput"><span class="identifier">__</span></code>
        is technically UB. I do not expect you to encounter any real problems if
        you use <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">range_adaptor_closure</span></code> with GCC 12, but
        I thought you should know.
      </p></td></tr>
</table></div>
<h4>
<a name="boost_stlinterfaces.tutorial__view_adaptors.h0"></a>
      <span class="phrase"><a name="boost_stlinterfaces.tutorial__view_adaptors.example___code__phrase_role__identifier__all__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="tutorial__view_adaptors.html#boost_stlinterfaces.tutorial__view_adaptors.example___code__phrase_role__identifier__all__phrase__phrase_role__special______phrase___code_">Example:
      <code class="computeroutput"><span class="identifier">all</span><span class="special">()</span></code></a>
    </h4>
<p>
      Let's take a look at a very simple view adaptor, <code class="computeroutput"><span class="identifier">all</span><span class="special">()</span></code>. <code class="computeroutput"><span class="identifier">all</span><span class="special">()</span></code> is a simplified version of <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">all</span><span class="special">()</span></code>
      that only works with lvalues.
    </p>
<p>
      First, we need a small amount of C++20 backported for use in earlier build
      modes:
    </p>
<p>
</p>
<pre class="programlisting"><span class="comment">// These act as stand-ins for std::ranges::iterator_t and -sentinel_t; we</span>
<span class="comment">// need these in C++17 and earlier.  They are not really complete, because</span>
<span class="comment">// they ignore free implementations of begin() and end().  This means they</span>
<span class="comment">// don't support builtin arrays, or other ranges that have ADL-findable</span>
<span class="comment">// begin() and end().  If you make your own versions, you should probably</span>
<span class="comment">// use the boost::begin() and -end() from Boost.Range, or the</span>
<span class="comment">// implementations from range-v3.</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">using</span> <span class="identifier">iterator_t</span> <span class="special">=</span> <span class="keyword">decltype</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">declval</span><span class="special">&lt;</span><span class="identifier">T</span> <span class="special">&amp;&gt;().</span><span class="identifier">begin</span><span class="special">());</span>
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">using</span> <span class="identifier">sentinel_t</span> <span class="special">=</span> <span class="keyword">decltype</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">declval</span><span class="special">&lt;</span><span class="identifier">T</span> <span class="special">&amp;&gt;().</span><span class="identifier">end</span><span class="special">());</span>
</pre>
<p>
    </p>
<p>
      Here is the view type itself:
    </p>
<p>
</p>
<pre class="programlisting">    <span class="comment">// This type allows us to implement a simplified version of the</span>
    <span class="comment">// std::views::all range adaptor for pre-C++20 builds.  Instead of</span>
    <span class="comment">// producing different kinds of ranges based on whether R is a</span>
    <span class="comment">// std::ranges::view, or would be better represented as a</span>
    <span class="comment">// std::ranges::ref_view or std::ranges::owning_view, it just grabs</span>
    <span class="comment">// begin() and end() out of R.  It also uses member-begin() and -end(), so</span>
    <span class="comment">// it doesn't work with builtin arrays.  It should probably use</span>
    <span class="comment">// boost::begin() and -end(), or something comparable.</span>
    <span class="comment">//</span>
    <span class="comment">// We constrain the template to only accept object-types, so that we don't</span>
    <span class="comment">// instantiate all_view with pointer or reference types.  We should also</span>
    <span class="comment">// require that R have .begin() and .end() members, but this is an</span>
    <span class="comment">// intentionally simplified example.</span>
    <span class="comment">//</span>
    <span class="comment">// We're putting the view in a detail namespace, because we don't expect</span>
    <span class="comment">// users to use our view directly; they should use the associated view</span>
    <span class="comment">// adaptor instead.  If you also want users to directly construct your</span>
    <span class="comment">// view-type, you would move it out of detail::.</span>
    <span class="comment">//</span>
    <span class="comment">// If you want to make views and view adaptors that will work with</span>
    <span class="comment">// pre-C++20 code, and then provide concept constraints in C++20 and</span>
    <span class="comment">// later, this is a reasonable pattern -- write the template-head twice:</span>
    <span class="comment">// once for C++20 concepts, and one for SFINAE.  Note that</span>
    <span class="comment">// BOOST_STL_INTERFACES_USE_CONCEPTS includes defined(__cpp_lib_concepts)</span>
    <span class="comment">// &amp;&amp; defined(__cpp_lib_ranges), and any preprocessor predicate you use</span>
    <span class="comment">// should as well.</span>
<span class="preprocessor">#if</span> <span class="identifier">BOOST_STL_INTERFACES_USE_CONCEPTS</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">R</span><span class="special">&gt;</span>
    <span class="identifier">requires</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_object_v</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;</span>
<span class="preprocessor">#else</span>
    <span class="keyword">template</span><span class="special">&lt;</span>
        <span class="keyword">typename</span> <span class="identifier">R</span><span class="special">,</span>
        <span class="keyword">typename</span> <span class="identifier">Enable</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">enable_if_t</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_object</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">&gt;&gt;</span>
<span class="preprocessor">#endif</span>
    <span class="keyword">struct</span> <span class="identifier">all_view</span> <span class="special">:</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">view_interface</span><span class="special">&lt;</span><span class="identifier">all_view</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;&gt;</span>
    <span class="special">{</span>
        <span class="keyword">using</span> <span class="identifier">iterator</span> <span class="special">=</span> <span class="identifier">iterator_t</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;;</span>
        <span class="keyword">using</span> <span class="identifier">sentinel</span> <span class="special">=</span> <span class="identifier">sentinel_t</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;;</span>

        <span class="comment">// Here, we want a constructor that takes a forwarding reference, so</span>
        <span class="comment">// we introduce a new template parameter R2, and constrain it to be</span>
        <span class="comment">// the same as R.  The int parameter is there to prevent getting in</span>
        <span class="comment">// the way of the special member functions like the copy constructor.</span>
        <span class="comment">// Since we don't want users directly constructing this type anyway,</span>
        <span class="comment">// the non-ideal ergonomics of this extra int don't matter.</span>
<span class="preprocessor">#if</span> <span class="identifier">BOOST_STL_INTERFACES_USE_CONCEPTS</span>
        <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">R2</span><span class="special">&gt;</span>
        <span class="identifier">requires</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same_v</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">R2</span><span class="special">&gt;,</span> <span class="identifier">R</span><span class="special">&gt;</span>
<span class="preprocessor">#else</span>
        <span class="keyword">template</span><span class="special">&lt;</span>
            <span class="keyword">typename</span> <span class="identifier">R2</span><span class="special">,</span>
            <span class="keyword">typename</span> <span class="identifier">E</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">enable_if_t</span><span class="special">&lt;</span>
                <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">R2</span><span class="special">&gt;,</span> <span class="identifier">R</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">&gt;&gt;</span>
<span class="preprocessor">#endif</span>
        <span class="keyword">explicit</span> <span class="identifier">all_view</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">R2</span> <span class="special">&amp;&amp;</span> <span class="identifier">r</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">first_</span><span class="special">(</span><span class="identifier">r</span><span class="special">.</span><span class="identifier">begin</span><span class="special">()),</span> <span class="identifier">last_</span><span class="special">(</span><span class="identifier">r</span><span class="special">.</span><span class="identifier">end</span><span class="special">())</span> <span class="special">{}</span>

        <span class="identifier">iterator</span> <span class="identifier">begin</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">first_</span><span class="special">;</span> <span class="special">}</span>
        <span class="identifier">sentinel</span> <span class="identifier">end</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">last_</span><span class="special">;</span> <span class="special">}</span>

    <span class="keyword">private</span><span class="special">:</span>
        <span class="identifier">iterator</span> <span class="identifier">first_</span><span class="special">;</span>
        <span class="identifier">sentinel</span> <span class="identifier">last_</span><span class="special">;</span>
    <span class="special">};</span>

    <span class="comment">// This just makes out implementations below a bit easier to write.</span>
<span class="preprocessor">#if</span> <span class="identifier">defined</span><span class="special">(</span><span class="identifier">__cpp_deduction_guides</span><span class="special">)</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">R</span><span class="special">&gt;</span>
    <span class="identifier">all_view</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">R</span> <span class="special">&amp;&amp;)-&gt;</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">all_view</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;&gt;;</span>
<span class="preprocessor">#endif</span>
</pre>
<p>
    </p>
<p>
      If we want to make our view adaptor in the style of the standard library, we
      need an impl-<code class="computeroutput"><span class="keyword">struct</span></code>:
    </p>
<p>
</p>
<pre class="programlisting"><span class="comment">// For C++20 views, there is usually some type like this.  This type</span>
<span class="comment">// implements the functions that construct our view.  An invocable object</span>
<span class="comment">// that uses this implementation will follow.  We need to inherit from</span>
<span class="comment">// range_adaptor_closure to make our view adaptor compatible with other</span>
<span class="comment">// view adaptors using the operator| "pipe" syntax.</span>
<span class="keyword">struct</span> <span class="identifier">all_impl</span> <span class="special">:</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">range_adaptor_closure</span><span class="special">&lt;</span><span class="identifier">all_impl</span><span class="special">&gt;</span>
<span class="special">{</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">R</span><span class="special">&gt;</span>
    <span class="keyword">constexpr</span> <span class="keyword">auto</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">R</span> <span class="special">&amp;&amp;</span> <span class="identifier">r</span><span class="special">)</span> <span class="keyword">const</span>
    <span class="special">{</span>
        <span class="comment">// The use of std::remove_reference is important, so that we</span>
        <span class="comment">// instantiate all_view with a non-reference type.  It is also</span>
        <span class="comment">// important not to use std::decay or std::remove_cvref here</span>
        <span class="comment">// instead.  If you do that and you pass a T const &amp; r, you'll end</span>
        <span class="comment">// up trying to initialize all_view&lt;T&gt;::first_ (which is a</span>
        <span class="comment">// T::iterator) from r.begin(), which is a T::const_iterator.</span>
        <span class="comment">// That won't work.</span>
        <span class="keyword">return</span> <span class="identifier">all_view</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;&gt;(</span><span class="number">0</span><span class="special">,</span> <span class="special">(</span><span class="identifier">R</span> <span class="special">&amp;&amp;)</span> <span class="identifier">r</span><span class="special">);</span>
    <span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
    </p>
<p>
      ... followed by an invocable object:
    </p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Here we create the actual invocable that the user will call.  It is just a</span>
<span class="comment">// constexpr all_impl variable.  Before C++17, you need to put it in an</span>
<span class="comment">// anonymous namespace to avoid violating the ODR. With this in scope, the</span>
<span class="comment">// user has everything necessary to use old_all().  I called it old_all(),</span>
<span class="comment">// because there's an even easier way to do this, as shown with all() below.</span>
<span class="preprocessor">#if</span> <span class="identifier">defined</span><span class="special">(</span><span class="identifier">__cpp_inline_variables</span><span class="special">)</span>
<span class="keyword">inline</span> <span class="keyword">constexpr</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">all_impl</span> <span class="identifier">old_all</span><span class="special">;</span>
<span class="preprocessor">#else</span>
<span class="keyword">namespace</span> <span class="special">{</span>
    <span class="keyword">constexpr</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">all_impl</span> <span class="identifier">old_all</span><span class="special">;</span>
<span class="special">}</span>
<span class="preprocessor">#endif</span>
</pre>
<p>
    </p>
<p>
      With these definitions, we can use <code class="computeroutput"><span class="identifier">old_all</span><span class="special">()</span></code> with the standard range adaptors:
    </p>
<pre class="programlisting"><span class="keyword">for</span> <span class="special">(</span><span class="keyword">auto</span> <span class="identifier">x</span> <span class="special">:</span> <span class="identifier">old_all</span><span class="special">(</span><span class="identifier">range</span><span class="special">)</span> <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">reverse</span><span class="special">)</span> <span class="special">{</span>
    <span class="comment">// etc.</span>
<span class="special">}</span>
</pre>
<p>
      However, Boost.STLInterfaces provides a simpler facility, based on the example
      in <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2387r3.html" target="_top">P2387</a>:
    </p>
<p>
</p>
<pre class="programlisting"><span class="comment">// This is the preferred way to make a view adaptor.  We can use a simple</span>
<span class="comment">// template called closure that already inherits from</span>
<span class="comment">// boost::stl_interfaces::range_adaptor_closure, and takes any function that</span>
<span class="comment">// can construct a closure from a given range.  In this case, our closure is</span>
<span class="comment">// just an all_view.  Later we'll see other kinds of closures.</span>
<span class="keyword">inline</span> <span class="keyword">constexpr</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">closure</span> <span class="identifier">all</span> <span class="special">=</span> <span class="special">[]&lt;</span><span class="keyword">typename</span> <span class="identifier">R</span><span class="special">&gt;(</span><span class="identifier">R</span> <span class="special">&amp;&amp;</span> <span class="identifier">r</span><span class="special">)</span> <span class="special">{</span>
    <span class="keyword">return</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">all_view</span><span class="special">(</span><span class="number">0</span><span class="special">,</span> <span class="special">(</span><span class="identifier">R</span> <span class="special">&amp;&amp;)</span> <span class="identifier">r</span><span class="special">);</span>
<span class="special">};</span>
</pre>
<p>
    </p>
<p>
      This does everything that <code class="computeroutput"><span class="identifier">all_impl</span></code>
      and <code class="computeroutput"><span class="identifier">old_all</span></code> (combined) do above,
      but with a lot less typing. From here on, we'll use <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">closure</span></code>
      instead of the more verbose technique.
    </p>
<p>
      Finally, we should make sure <code class="computeroutput"><span class="identifier">all_view</span></code>
      is treated as a borrowed range:
    </p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Any view that you make that is a proper view -- that is, it does not own</span>
<span class="comment">// the elements between its .begin() and .end() -- should be designated as a</span>
<span class="comment">// borrowed range, so that the std::ranges code treats is properly.  Without</span>
<span class="comment">// this, std::ranges code will assume that .begin() taken from an rvalue</span>
<span class="comment">// reference to your view type is a dangling iterator.</span>
<span class="comment">//</span>
<span class="comment">// As an example of this behavior, say you call</span>
<span class="comment">// std::ranges::find(std::vector&lt;int&gt;{}, 42).  The result will be a</span>
<span class="comment">// std::dangling instead of an iterator, because any iterator you pull out of</span>
<span class="comment">// a std::vector&lt;int&gt; &amp;&amp; is potentially a dangling reference to an element of</span>
<span class="comment">// a temporary std::vector&lt;int&gt;.</span>
<span class="preprocessor">#if</span> <span class="identifier">BOOST_STL_INTERFACES_USE_CONCEPTS</span>
<span class="keyword">namespace</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ranges</span> <span class="special">{</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">View</span><span class="special">&gt;</span>
    <span class="keyword">inline</span> <span class="keyword">constexpr</span> <span class="keyword">bool</span> <span class="identifier">enable_borrowed_range</span><span class="special">&lt;</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">all_view</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;&gt;</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span>
<span class="special">}</span>
<span class="preprocessor">#endif</span>
</pre>
<p>
    </p>
<h4>
<a name="boost_stlinterfaces.tutorial__view_adaptors.h1"></a>
      <span class="phrase"><a name="boost_stlinterfaces.tutorial__view_adaptors.example___code__phrase_role__identifier__reverse__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="tutorial__view_adaptors.html#boost_stlinterfaces.tutorial__view_adaptors.example___code__phrase_role__identifier__reverse__phrase__phrase_role__special______phrase___code_">Example:
      <code class="computeroutput"><span class="identifier">reverse</span><span class="special">()</span></code></a>
    </h4>
<p>
      <code class="computeroutput"><span class="identifier">reverse</span><span class="special">()</span></code>
      is more interesting than <code class="computeroutput"><span class="identifier">all</span><span class="special">()</span></code>, in that it does something more useful than
      simple adaptation. It is still very simple; all it does is provide a reversed
      view of a given view. Here is its definition:
    </p>
<p>
</p>
<pre class="programlisting">    <span class="comment">// We need to treat iterator/sentinel ranges differently from iterator</span>
    <span class="comment">// ranges (a.k.a. common_ranges).  If the iterator and sentinel are</span>
    <span class="comment">// different types, we need to advance the iterator to the end of the</span>
    <span class="comment">// range before we can move through the range in reverse.</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">bool</span> <span class="identifier">CommonRange</span><span class="special">&gt;</span>
    <span class="keyword">struct</span> <span class="identifier">set_rev_rng_first</span>
    <span class="special">{</span>
        <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">V</span><span class="special">&gt;</span>
        <span class="keyword">static</span> <span class="keyword">auto</span> <span class="identifier">call</span><span class="special">(</span><span class="identifier">V</span> <span class="keyword">const</span> <span class="special">&amp;</span> <span class="identifier">v</span><span class="special">)</span>
        <span class="special">{</span>
            <span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">make_reverse_iterator</span><span class="special">(</span><span class="identifier">v</span><span class="special">.</span><span class="identifier">end</span><span class="special">());</span>
        <span class="special">}</span>
    <span class="special">};</span>

    <span class="keyword">template</span><span class="special">&lt;&gt;</span>
    <span class="keyword">struct</span> <span class="identifier">set_rev_rng_first</span><span class="special">&lt;</span><span class="keyword">false</span><span class="special">&gt;</span>
    <span class="special">{</span>
        <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">V</span><span class="special">&gt;</span>
        <span class="keyword">static</span> <span class="keyword">auto</span> <span class="identifier">call</span><span class="special">(</span><span class="identifier">V</span> <span class="keyword">const</span> <span class="special">&amp;</span> <span class="identifier">v</span><span class="special">)</span>
        <span class="special">{</span>
            <span class="keyword">auto</span> <span class="identifier">v_f</span> <span class="special">=</span> <span class="identifier">v</span><span class="special">.</span><span class="identifier">begin</span><span class="special">();</span>
            <span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">v_l</span> <span class="special">=</span> <span class="identifier">v</span><span class="special">.</span><span class="identifier">end</span><span class="special">();</span>
            <span class="keyword">while</span> <span class="special">(</span><span class="identifier">v_f</span> <span class="special">!=</span> <span class="identifier">v_l</span><span class="special">)</span> <span class="special">{</span>
                <span class="special">++</span><span class="identifier">v_f</span><span class="special">;</span>
            <span class="special">}</span>
            <span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">make_reverse_iterator</span><span class="special">(</span><span class="identifier">v_f</span><span class="special">);</span>
        <span class="special">}</span>
    <span class="special">};</span>

    <span class="comment">// This view reverses whatever view you construct it from.  Unlike</span>
    <span class="comment">// all_view, it requires that it be constructed from a view.  This is</span>
    <span class="comment">// enforced through a constraint in C++20 and later, but is left up to the</span>
    <span class="comment">// user in earlier C++ modes.</span>
<span class="preprocessor">#if</span> <span class="identifier">BOOST_STL_INTERFACES_USE_CONCEPTS</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ranges</span><span class="special">::</span><span class="identifier">view</span> <span class="identifier">View</span><span class="special">&gt;</span>
    <span class="identifier">requires</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_object_v</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;</span>
<span class="preprocessor">#else</span>
    <span class="keyword">template</span><span class="special">&lt;</span>
        <span class="keyword">typename</span> <span class="identifier">View</span><span class="special">,</span>
        <span class="keyword">typename</span> <span class="identifier">Enable</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">enable_if_t</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_object</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">&gt;&gt;</span>
<span class="preprocessor">#endif</span>
    <span class="keyword">struct</span> <span class="identifier">reverse_view</span>
        <span class="special">:</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">view_interface</span><span class="special">&lt;</span><span class="identifier">reverse_view</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;&gt;</span>
    <span class="special">{</span>
        <span class="keyword">using</span> <span class="identifier">view_iterator</span> <span class="special">=</span> <span class="identifier">iterator_t</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;;</span>
        <span class="keyword">using</span> <span class="identifier">view_sentinel</span> <span class="special">=</span> <span class="identifier">sentinel_t</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;;</span>

        <span class="comment">// This would be better off as a constraint in C++20 and later.</span>
        <span class="keyword">static_assert</span><span class="special">(</span>
            <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_base_of</span><span class="special">&lt;</span>
                <span class="identifier">std</span><span class="special">::</span><span class="identifier">bidirectional_iterator_tag</span><span class="special">,</span>
                <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">iterator_traits</span><span class="special">&lt;</span>
                    <span class="identifier">view_iterator</span><span class="special">&gt;::</span><span class="identifier">iterator_category</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">,</span>
            <span class="string">"A reversed view must have bidirectional iterators."</span><span class="special">);</span>

        <span class="keyword">using</span> <span class="identifier">iterator</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">reverse_iterator</span><span class="special">&lt;</span><span class="identifier">view_iterator</span><span class="special">&gt;;</span>

        <span class="keyword">constexpr</span> <span class="identifier">reverse_view</span><span class="special">()</span> <span class="special">=</span> <span class="keyword">default</span><span class="special">;</span>

<span class="preprocessor">#if</span> <span class="identifier">BOOST_STL_INTERFACES_USE_CONCEPTS</span>
        <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">V</span><span class="special">&gt;</span>
        <span class="identifier">requires</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same_v</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">V</span><span class="special">&gt;,</span> <span class="identifier">View</span><span class="special">&gt;</span>
<span class="preprocessor">#else</span>
        <span class="keyword">template</span><span class="special">&lt;</span>
            <span class="keyword">typename</span> <span class="identifier">V</span><span class="special">,</span>
            <span class="keyword">typename</span> <span class="identifier">E</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">enable_if_t</span><span class="special">&lt;</span>
                <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">V</span><span class="special">&gt;,</span> <span class="identifier">View</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">&gt;&gt;</span>
<span class="preprocessor">#endif</span>
        <span class="keyword">constexpr</span> <span class="identifier">reverse_view</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">V</span> <span class="special">&amp;&amp;</span> <span class="identifier">v</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">v_</span><span class="special">{(</span><span class="identifier">V</span> <span class="special">&amp;&amp;)</span> <span class="identifier">v</span><span class="special">}</span>
        <span class="special">{</span>
            <span class="comment">// To keep the code simpler, we just store the iterator to the end</span>
            <span class="comment">// of v, whether v is a common_range or has different iterator and</span>
            <span class="comment">// sentinel types.</span>
            <span class="identifier">first_</span> <span class="special">=</span> <span class="identifier">set_rev_rng_first</span><span class="special">&lt;</span>
                <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">view_iterator</span><span class="special">,</span> <span class="identifier">view_sentinel</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">&gt;::</span><span class="identifier">call</span><span class="special">(</span><span class="identifier">v_</span><span class="special">);</span>
        <span class="special">}</span>

        <span class="keyword">constexpr</span> <span class="identifier">iterator</span> <span class="identifier">begin</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">first_</span><span class="special">;</span> <span class="special">}</span>
        <span class="keyword">constexpr</span> <span class="identifier">iterator</span> <span class="identifier">end</span><span class="special">()</span> <span class="keyword">const</span>
        <span class="special">{</span>
            <span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">make_reverse_iterator</span><span class="special">(</span><span class="identifier">v_</span><span class="special">.</span><span class="identifier">begin</span><span class="special">());</span>
        <span class="special">}</span>

        <span class="comment">// Return the underlying view that this view reverses.</span>
        <span class="keyword">constexpr</span> <span class="identifier">View</span> <span class="identifier">base</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">v_</span><span class="special">;</span> <span class="special">}</span>

    <span class="keyword">private</span><span class="special">:</span>
        <span class="identifier">View</span> <span class="identifier">v_</span> <span class="special">=</span> <span class="identifier">View</span><span class="special">();</span>
        <span class="identifier">iterator</span> <span class="identifier">first_</span><span class="special">;</span>
    <span class="special">};</span>

    <span class="comment">// is_reverse_view lets us detect construction of a reverse_view from</span>
    <span class="comment">// another reverse_view, and take appropriate action (see below).</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
    <span class="keyword">struct</span> <span class="identifier">is_reverse_view</span> <span class="special">:</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">false_type</span>
    <span class="special">{};</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
    <span class="keyword">struct</span> <span class="identifier">is_reverse_view</span><span class="special">&lt;</span><span class="identifier">reverse_view</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;</span> <span class="special">:</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">true_type</span>
    <span class="special">{};</span>

<span class="preprocessor">#if</span> <span class="identifier">defined</span><span class="special">(</span><span class="identifier">__cpp_deduction_guides</span><span class="special">)</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">R</span><span class="special">&gt;</span>
    <span class="identifier">reverse_view</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">R</span> <span class="special">&amp;&amp;)-&gt;</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">reverse_view</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;&gt;;</span>
<span class="preprocessor">#endif</span>
</pre>
<p>
    </p>
<p>
      As with <code class="computeroutput"><span class="identifier">all</span><span class="special">()</span></code>,
      we define a <code class="computeroutput"><span class="identifier">closure</span></code> object
      <code class="computeroutput"><span class="identifier">reverse</span></code> that we can invoke:
    </p>
<p>
</p>
<pre class="programlisting"><span class="comment">// We want to condition how we construct our view based on whether R is itself</span>
<span class="comment">// a reverse_view.  If R is a reverse_view, just return the view it's</span>
<span class="comment">// reversing.</span>
<span class="comment">//</span>
<span class="comment">// In C++20 and later, you might want to constrain this lambda to require that</span>
<span class="comment">// R is a std::ranges::view, since that's what reverse_view requires.</span>
<span class="keyword">inline</span> <span class="keyword">constexpr</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">closure</span> <span class="identifier">reverse</span> <span class="special">=</span>
    <span class="special">[]&lt;</span><span class="keyword">typename</span> <span class="identifier">R</span><span class="special">&gt;(</span><span class="identifier">R</span> <span class="special">&amp;&amp;</span> <span class="identifier">r</span><span class="special">)</span> <span class="special">{</span>
        <span class="keyword">if</span> <span class="keyword">constexpr</span> <span class="special">(</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">is_reverse_view</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">decay_t</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;&gt;::</span><span class="identifier">value</span><span class="special">)</span> <span class="special">{</span>
            <span class="keyword">return</span> <span class="special">((</span><span class="identifier">R</span> <span class="special">&amp;&amp;)</span> <span class="identifier">r</span><span class="special">).</span><span class="identifier">base</span><span class="special">();</span>
        <span class="special">}</span> <span class="keyword">else</span> <span class="special">{</span>
            <span class="keyword">return</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">reverse_view</span><span class="special">(</span><span class="number">0</span><span class="special">,</span> <span class="special">(</span><span class="identifier">R</span> <span class="special">&amp;&amp;)</span> <span class="identifier">r</span><span class="special">);</span>
        <span class="special">}</span>
    <span class="special">};</span>
</pre>
<p>
    </p>
<p>
      And again, we do this:
    </p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Don't forget to designate our view as a borrowed range.</span>
<span class="preprocessor">#if</span> <span class="identifier">BOOST_STL_INTERFACES_USE_CONCEPTS</span>
<span class="keyword">namespace</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ranges</span> <span class="special">{</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">View</span><span class="special">&gt;</span>
    <span class="keyword">inline</span> <span class="keyword">constexpr</span> <span class="keyword">bool</span> <span class="identifier">enable_borrowed_range</span><span class="special">&lt;</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">reverse_view</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;&gt;</span> <span class="special">=</span>
        <span class="keyword">true</span><span class="special">;</span>
<span class="special">}</span>
<span class="preprocessor">#endif</span>
</pre>
<p>
    </p>
<p>
      Now that we have <code class="computeroutput"><span class="identifier">all</span><span class="special">()</span></code>
      and <code class="computeroutput"><span class="identifier">reverse</span><span class="special">()</span></code>,
      we can write this:
    </p>
<pre class="programlisting"><span class="keyword">for</span> <span class="special">(</span><span class="keyword">auto</span> <span class="identifier">x</span> <span class="special">:</span> <span class="identifier">all</span><span class="special">(</span><span class="identifier">range</span><span class="special">)</span> <span class="special">|</span> <span class="identifier">reverse</span><span class="special">)</span> <span class="special">{</span>
    <span class="comment">// etc.</span>
<span class="special">}</span>
</pre>
<p>
      Since everythinge is <code class="computeroutput"><span class="identifier">std</span></code>-compatible,
      we can also write:
    </p>
<pre class="programlisting"><span class="keyword">for</span> <span class="special">(</span><span class="keyword">auto</span> <span class="identifier">x</span> <span class="special">:</span> <span class="identifier">all</span><span class="special">(</span><span class="identifier">range</span><span class="special">)</span> <span class="special">|</span> <span class="identifier">reverse</span> <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">reverse</span><span class="special">)</span> <span class="special">{</span>
    <span class="comment">// etc.</span>
<span class="special">}</span>
</pre>
<p>
      Unfortunately, <code class="computeroutput"><span class="identifier">reverse</span></code> and
      <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">reverse</span></code>
      know nothing about one another, so <code class="computeroutput"><span class="identifier">all</span><span class="special">(</span><span class="identifier">range</span><span class="special">)</span>
      <span class="special">|</span> <span class="identifier">reverse</span>
      <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">reverse</span></code> does not reduce to <code class="computeroutput"><span class="identifier">all</span><span class="special">(</span><span class="identifier">range</span><span class="special">)</span></code> as both <code class="computeroutput"><span class="identifier">all</span><span class="special">(</span><span class="identifier">range</span><span class="special">)</span>
      <span class="special">|</span> <span class="identifier">reverse</span>
      <span class="special">|</span> <span class="identifier">reverse</span></code>
      and <code class="computeroutput"><span class="identifier">all</span><span class="special">(</span><span class="identifier">range</span><span class="special">)</span> <span class="special">|</span>
      <span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">reverse</span>
      <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">views</span><span class="special">::</span><span class="identifier">reverse</span></code> do.
    </p>
<h4>
<a name="boost_stlinterfaces.tutorial__view_adaptors.h2"></a>
      <span class="phrase"><a name="boost_stlinterfaces.tutorial__view_adaptors.example___code__phrase_role__identifier__take__phrase__phrase_role__special______phrase___code_"></a></span><a class="link" href="tutorial__view_adaptors.html#boost_stlinterfaces.tutorial__view_adaptors.example___code__phrase_role__identifier__take__phrase__phrase_role__special______phrase___code_">Example:
      <code class="computeroutput"><span class="identifier">take</span><span class="special">()</span></code></a>
    </h4>
<p>
      <code class="computeroutput"><span class="identifier">take_view</span></code> is a little different
      from the previous two views, in that it takes more than just a range to construct
      it — it is constructed from a range and a count. Any time a view takes
      more than just a range to construct, it is usually nice to use it with all
      the parameters besides the view itself. For instance, you might want to use
      take as <code class="computeroutput"><span class="identifier">v</span> <span class="special">|</span>
      <span class="identifier">take</span><span class="special">(</span><span class="number">42</span><span class="special">)</span></code>, or as <code class="computeroutput"><span class="identifier">take</span><span class="special">(</span><span class="identifier">v</span><span class="special">,</span> <span class="number">42</span><span class="special">)</span></code>
      (more on this below). Here is our definition of <code class="computeroutput"><span class="identifier">take_view</span></code>:
    </p>
<p>
</p>
<pre class="programlisting">    <span class="comment">// This is a really simple iterator that converts the given iterator Iter</span>
    <span class="comment">// to a forward_iterator that counts how many times it has ben</span>
    <span class="comment">// incremented.  It counts down from an initial count to zero.</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Iter</span><span class="special">&gt;</span>
    <span class="keyword">struct</span> <span class="identifier">take_iterator</span>
        <span class="special">:</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">iterator_interface</span><span class="special">&lt;</span>
<span class="preprocessor">#if</span> <span class="special">!</span><span class="identifier">BOOST_STL_INTERFACES_USE_DEDUCED_THIS</span>
              <span class="identifier">take_iterator</span><span class="special">&lt;</span><span class="identifier">Iter</span><span class="special">&gt;,</span>
<span class="preprocessor">#endif</span>
              <span class="identifier">std</span><span class="special">::</span><span class="identifier">forward_iterator_tag</span><span class="special">,</span>
              <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">iterator_traits</span><span class="special">&lt;</span><span class="identifier">Iter</span><span class="special">&gt;::</span><span class="identifier">value_type</span><span class="special">,</span>
              <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">iterator_traits</span><span class="special">&lt;</span><span class="identifier">Iter</span><span class="special">&gt;::</span><span class="identifier">reference</span><span class="special">,</span>
              <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">iterator_traits</span><span class="special">&lt;</span><span class="identifier">Iter</span><span class="special">&gt;::</span><span class="identifier">pointer</span><span class="special">,</span>
              <span class="keyword">typename</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">iterator_traits</span><span class="special">&lt;</span><span class="identifier">Iter</span><span class="special">&gt;::</span><span class="identifier">difference_type</span><span class="special">&gt;</span>
    <span class="special">{</span>
        <span class="keyword">constexpr</span> <span class="identifier">take_iterator</span><span class="special">()</span> <span class="special">=</span> <span class="keyword">default</span><span class="special">;</span>
        <span class="keyword">constexpr</span> <span class="keyword">explicit</span> <span class="identifier">take_iterator</span><span class="special">(</span><span class="identifier">Iter</span> <span class="identifier">it</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">n</span><span class="special">)</span> <span class="special">:</span>
            <span class="identifier">it_</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">it</span><span class="special">)),</span> <span class="identifier">n_</span><span class="special">(</span><span class="identifier">n</span><span class="special">)</span>
        <span class="special">{}</span>

        <span class="keyword">constexpr</span> <span class="identifier">Iter</span> <span class="identifier">base</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">it_</span><span class="special">;</span> <span class="special">}</span>
        <span class="keyword">constexpr</span> <span class="keyword">int</span> <span class="identifier">count</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">n_</span><span class="special">;</span> <span class="special">}</span>

        <span class="keyword">constexpr</span> <span class="identifier">take_iterator</span> <span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">++()</span>
        <span class="special">{</span>
            <span class="special">++</span><span class="identifier">it_</span><span class="special">;</span>
            <span class="special">--</span><span class="identifier">n_</span><span class="special">;</span>
            <span class="keyword">return</span> <span class="special">*</span><span class="keyword">this</span><span class="special">;</span>
        <span class="special">}</span>

    <span class="keyword">private</span><span class="special">:</span>
        <span class="keyword">friend</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">access</span><span class="special">;</span>
        <span class="keyword">constexpr</span> <span class="identifier">Iter</span> <span class="special">&amp;</span> <span class="identifier">base_reference</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">it_</span><span class="special">;</span> <span class="special">}</span>
        <span class="keyword">constexpr</span> <span class="identifier">Iter</span> <span class="keyword">const</span> <span class="special">&amp;</span> <span class="identifier">base_reference</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">it_</span><span class="special">;</span> <span class="special">}</span>

        <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Iter2</span><span class="special">&gt;</span>
        <span class="keyword">friend</span> <span class="keyword">struct</span> <span class="identifier">take_iterator</span><span class="special">;</span>

        <span class="identifier">Iter</span> <span class="identifier">it_</span><span class="special">;</span>
        <span class="keyword">int</span> <span class="identifier">n_</span><span class="special">;</span>
    <span class="special">};</span>

    <span class="comment">// This sentinel compares equal to any take_iterator whose count has</span>
    <span class="comment">// reached zero, or the end of the underlying range if that comes first.</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Sentinel</span><span class="special">&gt;</span>
    <span class="keyword">struct</span> <span class="identifier">take_sentinel</span>
    <span class="special">{</span>
        <span class="identifier">take_sentinel</span><span class="special">()</span> <span class="special">=</span> <span class="keyword">default</span><span class="special">;</span>
        <span class="keyword">explicit</span> <span class="identifier">take_sentinel</span><span class="special">(</span><span class="identifier">Sentinel</span> <span class="identifier">sent</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">sent_</span><span class="special">(</span><span class="identifier">sent</span><span class="special">)</span> <span class="special">{}</span>

        <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Iter</span><span class="special">&gt;</span>
        <span class="keyword">friend</span> <span class="keyword">constexpr</span> <span class="keyword">bool</span>
        <span class="keyword">operator</span><span class="special">==(</span><span class="identifier">take_iterator</span><span class="special">&lt;</span><span class="identifier">Iter</span><span class="special">&gt;</span> <span class="identifier">it</span><span class="special">,</span> <span class="identifier">take_sentinel</span> <span class="identifier">s</span><span class="special">)</span>
        <span class="special">{</span>
            <span class="keyword">return</span> <span class="special">!</span><span class="identifier">it</span><span class="special">.</span><span class="identifier">count</span><span class="special">()</span> <span class="special">||</span> <span class="identifier">it</span><span class="special">.</span><span class="identifier">base</span><span class="special">()</span> <span class="special">==</span> <span class="identifier">s</span><span class="special">.</span><span class="identifier">sent_</span><span class="special">;</span>
        <span class="special">}</span>
        <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">Iter</span><span class="special">&gt;</span>
        <span class="keyword">friend</span> <span class="keyword">constexpr</span> <span class="keyword">bool</span>
        <span class="keyword">operator</span><span class="special">!=(</span><span class="identifier">take_iterator</span><span class="special">&lt;</span><span class="identifier">Iter</span><span class="special">&gt;</span> <span class="identifier">it</span><span class="special">,</span> <span class="identifier">take_sentinel</span> <span class="identifier">s</span><span class="special">)</span>
        <span class="special">{</span>
            <span class="keyword">return</span> <span class="special">!(</span><span class="identifier">it</span> <span class="special">==</span> <span class="identifier">s</span><span class="special">);</span>
        <span class="special">}</span>

    <span class="keyword">private</span><span class="special">:</span>
        <span class="identifier">Sentinel</span> <span class="identifier">sent_</span><span class="special">;</span>
    <span class="special">};</span>

    <span class="comment">// The take_iterator and take_sentinel templates do all the hard work,</span>
    <span class="comment">// which leaves take_view quite simple.</span>
<span class="preprocessor">#if</span> <span class="identifier">BOOST_STL_INTERFACES_USE_CONCEPTS</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">ranges</span><span class="special">::</span><span class="identifier">view</span> <span class="identifier">View</span><span class="special">&gt;</span>
    <span class="identifier">requires</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_object_v</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;</span>
<span class="preprocessor">#else</span>
    <span class="keyword">template</span><span class="special">&lt;</span>
        <span class="keyword">typename</span> <span class="identifier">View</span><span class="special">,</span>
        <span class="keyword">typename</span> <span class="identifier">Enable</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">enable_if_t</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">is_object</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">&gt;&gt;</span>
<span class="preprocessor">#endif</span>
    <span class="keyword">struct</span> <span class="identifier">take_view</span> <span class="special">:</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">view_interface</span><span class="special">&lt;</span><span class="identifier">take_view</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;&gt;</span>
    <span class="special">{</span>
        <span class="keyword">using</span> <span class="identifier">iterator</span> <span class="special">=</span> <span class="identifier">take_iterator</span><span class="special">&lt;</span><span class="identifier">iterator_t</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;&gt;;</span>
        <span class="keyword">using</span> <span class="identifier">sentinel</span> <span class="special">=</span> <span class="identifier">take_sentinel</span><span class="special">&lt;</span><span class="identifier">sentinel_t</span><span class="special">&lt;</span><span class="identifier">View</span><span class="special">&gt;&gt;;</span>

        <span class="comment">// We don't need a phony initial int param for this constructor, since</span>
        <span class="comment">// it already takes two parameters; it won't get confused for a copy</span>
        <span class="comment">// or a move.  The count here is just an int to keep things simple.</span>
<span class="preprocessor">#if</span> <span class="identifier">BOOST_STL_INTERFACES_USE_CONCEPTS</span>
        <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">View2</span><span class="special">&gt;</span>
        <span class="identifier">requires</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same_v</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">View2</span><span class="special">&gt;,</span> <span class="identifier">View</span><span class="special">&gt;</span>
<span class="preprocessor">#else</span>
        <span class="keyword">template</span><span class="special">&lt;</span>
            <span class="keyword">typename</span> <span class="identifier">View2</span><span class="special">,</span>
            <span class="keyword">typename</span> <span class="identifier">E</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">enable_if_t</span><span class="special">&lt;</span>
                <span class="identifier">std</span><span class="special">::</span><span class="identifier">is_same</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">View2</span><span class="special">&gt;,</span> <span class="identifier">View</span><span class="special">&gt;::</span><span class="identifier">value</span><span class="special">&gt;&gt;</span>
<span class="preprocessor">#endif</span>
        <span class="keyword">explicit</span> <span class="identifier">take_view</span><span class="special">(</span><span class="identifier">View2</span> <span class="special">&amp;&amp;</span> <span class="identifier">r</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">n</span><span class="special">)</span> <span class="special">:</span>
            <span class="identifier">first_</span><span class="special">(</span><span class="identifier">r</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">n</span><span class="special">),</span> <span class="identifier">last_</span><span class="special">(</span><span class="identifier">r</span><span class="special">.</span><span class="identifier">end</span><span class="special">())</span>
        <span class="special">{}</span>

        <span class="identifier">iterator</span> <span class="identifier">begin</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">first_</span><span class="special">;</span> <span class="special">}</span>
        <span class="identifier">sentinel</span> <span class="identifier">end</span><span class="special">()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">last_</span><span class="special">;</span> <span class="special">}</span>

    <span class="keyword">private</span><span class="special">:</span>
        <span class="identifier">iterator</span> <span class="identifier">first_</span><span class="special">;</span>
        <span class="identifier">sentinel</span> <span class="identifier">last_</span><span class="special">;</span>
    <span class="special">};</span>

<span class="preprocessor">#if</span> <span class="identifier">defined</span><span class="special">(</span><span class="identifier">__cpp_deduction_guides</span><span class="special">)</span>
    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">R</span><span class="special">&gt;</span>
    <span class="identifier">take_view</span><span class="special">(</span><span class="identifier">R</span> <span class="special">&amp;&amp;,</span> <span class="keyword">int</span><span class="special">)-&gt;</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">take_view</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">remove_reference_t</span><span class="special">&lt;</span><span class="identifier">R</span><span class="special">&gt;&gt;;</span>
<span class="preprocessor">#endif</span>
</pre>
<p>
    </p>
<p>
      Now we need an invocable for users to call. Instead of using <code class="computeroutput"><span class="identifier">closure</span></code>, we use <code class="computeroutput"><span class="identifier">adaptor</span></code>:
    </p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Use the adaptor template to support calling the given lambda with either</span>
<span class="comment">// all the parameters or all the parameters after the first.</span>
<span class="keyword">inline</span> <span class="keyword">constexpr</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">stl_interfaces</span><span class="special">::</span><span class="identifier">adaptor</span> <span class="identifier">take</span> <span class="special">=</span>
    <span class="special">[]&lt;</span><span class="keyword">typename</span> <span class="identifier">R</span><span class="special">&gt;(</span><span class="identifier">R</span> <span class="special">&amp;&amp;</span> <span class="identifier">r</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">n</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">detail</span><span class="special">::</span><span class="identifier">take_view</span><span class="special">((</span><span class="identifier">R</span> <span class="special">&amp;&amp;)</span> <span class="identifier">r</span><span class="special">,</span> <span class="identifier">n</span><span class="special">);</span> <span class="special">};</span>
</pre>
<p>
    </p>
</div>
<div class="copyright-footer">Copyright © 2019 T. Zachary Laine<p>
        Distributed under the Boost Software License, Version 1.0. (See accompanying
        file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
      </p>
</div>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="tutorial___reverse_iterator_.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../stl_interfaces.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="tutorial___closure__and__adaptor_.html"><img src="../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>
